<template>
  <div ref="chatModal">
    <!-- 聊天区域 -->
    <div class="c-pt12" ref="chatBox" v-if="baseInfo">
      <!-- ai助理欢迎语句 -->
      <div class="c-pv15" v-if="baseInfo.name && (baseInfo.greeting || baseInfo.desc) && (baseInfo.isNewSession == 1)">
        <div class="c-flex-row c-aligni-center c-pb15 c-w100">
          <img class="c-hh60 c-ww60 c-brp50 c-mr12 c-object-fit-cover" :src="$addXossFilter(baseInfo.avatar, require('@/assets/defult270.png'))" alt="">
          <div class="c-w0 c-flex-grow1 c-text-ellipsis1 c-fs26 c-fw-b">{{baseInfo.name}}</div>
        </div>
        <div class="c-bg-white c-ph24 c-pv24 c-br16 c-br-tl0 c-text-hidde c-maxw c-inlineflex-column" v-if="baseInfo.greeting || baseInfo.desc">
          <p class="c-fs24">{{baseInfo.greeting}}</p>
        </div>
      </div>
      <!-- 聊天区域 -->
      <div :id="'messages' + index" v-for="(item, index) in messages" :key="item.record_id">
        <!-- 用户提问对话 -->
        <div class="c-pv15 c-flex-row c-justify-end" v-if="item.replyMethod == 0">
          <div class="c-inlineflex-column c-aligni-end">
            <div class="c-bg-xblue c-ph24 c-pv24 c-br16 c-br-tr0 c-text-hidde">
              <div class="c-fs24 c-fc-white c-wordBreakAll">{{ item.content }}</div>
            </div>
          </div>
        </div>
        <!-- ai助理回答 -->
        <div v-if="item.replyMethod != 0" class="c-pt15">
          <div class="c-flex-row c-aligni-center c-w100">
            <img class="c-hh60 c-ww60 c-brp50 c-mr12 c-object-fit-cover" :src="$addXossFilter(baseInfo.avatar, require('@/assets/defult270.png'))" alt="">
            <div class="c-w0 c-flex-grow1 c-text-ellipsis1 c-fs26 c-fw-b">{{baseInfo.name}}</div>
          </div>
          <div class="c-pv15 c-inlineflex-column c-maxw">
            <div class="c-bg-white c-ph24 c-pv24 c-br16 c-br-tl0 c-text-hidde">
              <div class="c-fs24 c-fc-xblack c-wordBreakAll markdown-box c-lh34" v-html="item.content"></div>
            </div>
          </div>
        </div>
      </div>
      <!-- 搜索问题状态请求 -->
      <div class="c-pv24 c-inlineflex-column" v-show="isSearch == 1">
        <div class="c-bg-white c-ph24 c-pv24 c-br24 c-br-tl0 c-text-hidde">
          <div class="c-fs24 c-fc-xblack c-wordBreakAll c-flex-row c-aligni-center">
            <img class="c-hh40 c-ww40 c-brp50 c-mr12" :src="require('@/assets/i/wap/ai/aiLoad.gif')" alt="">请稍等，我思考下…
          </div>
        </div>
      </div>
    </div>
    <!-- 底部提问输入区域 -->
    <div class="c-pv16 c-pf c-maxw640 c-center c-p-b0 c-p-l0 c-p-r0 c-hh112 c-bg-sgray c-ph24">
      <div class="c-flex-row c-aligni-center">
        <!-- 清除会话屏蔽 -->
        <!-- <div
          class="c-hh80 c-ww80 c-brp50 c-flex-row c-flex-center iconfont c-bg-white c-fs28 c-mr12 c-text-hidden"
          :class="messages && messages.length > 0 ? 'c-fc-xblack' : 'c-fc-gray'"
          @click="cleanSession">
          &#xe8a7;
        </div> -->
        <div class="c-br40 c-bg-white c-hh80 c-flex-grow1 c-w0 c-ph12 c-pv12 c-flex-row c-aligni-center">
          <input class="inputBox c-w0 c-flex-grow1 c-pl12" v-model="searchTxt" :disabled="isSearch == 1" autofocus="autofocus" type="text" placeholder="来和我对话吧" @keyup.enter="submitSearch" @focus="focusInput">
          <div
            class="c-hh54 c-ww54 c-brp50 c-flex-row c-flex-center c-bg-xblue c-ml12 c-text-hidden"
            v-show="searchTxt && searchTxt.length > 0"
            @click="submitSearch"
          >
            <i class="c-fs28 iconfont c-fc-white">&#xe8a8;</i>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script scoped>
import { utilJs } from "@/utils/common.js";
import FetchEventSource from '@/utils/fetchEventSource.js';
import markdownit from 'markdown-it';
let md = null; // 解析markdownit的对象
export default {
  name: 'aiChatCom',
  data() {
    return {
      searchTxt: '', // 搜索文案
      messages: [],
      baseInfo: null, // ai助理基本信息
      isSearch: 0, // 判断是否在搜索问题 -1 搜索失败 0搜索结束 1正在搜索
    }
  },
  props: {
    prodType: { // 产品类型
      type: Number,
      default: 0
    },
    prodId: { // 产品id
      type: Number,
      default: 0
    },
    subScene: { // 1-主页/微页面，2-底部导航，3-直播，4-公众号菜单，5-小程序，6-公众号
      type: Number,
      default: 1
    },
    aikbId: {
      type: String,
      default: ''
    },
    sort: {
      type: Number,
      default: 1
    }
  },
  mounted() {
    // 获取会话信息
    this.getDescribeBaseRelate();
    // 初始化markDown插件
    this.markdownItInit()
  },
  methods: {
    // 初始化markDown插件
    markdownItInit() {
      md = markdownit();
      // 特别样式针对表格
      md.renderer.rules.table_open = () => {
        return '<div class="c-content-scroll"><table>'
      }
      md.renderer.rules.table_close = () => {
        return '</table></div>'
      }
    },
    // 聚焦定位底部
    focusInput() {
      this.$nextTick(() => {
        this.domScrollIntoView();
      })
    },
    // 消息显示定位 超过一屏的数据定位到最新聊天
    domScrollIntoView() {
      setTimeout(() => {
        if (!this.$refs.chatBox) return
        const viewportHeight = document.documentElement.clientHeight;
        const elementHeight = this.$refs.chatBox.offsetHeight;
        if (elementHeight > viewportHeight - 110) { //  110是扣除底部按钮区域高度的值 + 顶部导航
          const dom = document.getElementById('messages' + (this.messages.length - 1));
          dom && dom.scrollIntoView({
            block: "start",
            behavior: "smooth",
          });
        }
      }, 300)
    },
    // 获取关联应用详情
    getDescribeBaseRelate() {
      let postUrl = `${global.apiurl}aiCreationCenter/describeBaseRelate`;
      let data = {
        scene: 1, // 1-知识店铺，2-微信生态
        subScene: this.subScene, // 1-主页/微页面，2-底部导航，3-直播，4-公众号菜单，5-小程序，6-公众号
        prodType: this.prodType,
        prodId: this.prodId,
        aikbId: this.aikbId
      }
      // 底部导航区分多个ai助理
      if (data.subScene == 2) data.sort = this.sort;
      utilJs.postMethod(postUrl, data, (res) => {
        // baseStatus，1-正常，2-过期，-1-删除
        if ([-1, 2].includes(res.baseStatus)) {
          this.$routerGo(this, "replace", {
            path: "/error/emptyPage",
            query: {
              from: "ai",
              info: '服务已暂停，无法查看'
            }
          });
          return;
        }
        this.baseInfo = res;
        this.$emit('baseRelate', res);
        if (this.baseInfo.isNewSession == 0) { // 新会话获取会话的历史记录
          this.getMessageList();
        }
      }, () => {
      });
    },
    // 获取历史信息列表，最多10轮历史数据
    getMessageList() {
      this.$loading.show({
        text: '加载中'
      });
      let postUrl = `${global.apiurl}aiCreationCenter/getMsgRecord`;
      const data = {
        sessionId: this.baseInfo.sessionId, // 会话id
      }
      utilJs.postMethod(postUrl, data, res => {
        this.messages = res.records;
        this.messages.forEach(item => {
          if (item.replyMethod != 0) {
            item.content = md.render(item.content);
          }
        })
        setTimeout(() => {
          this.domScrollIntoView();
        }, 300)
        this.$loading.hide();
      }, () => {
        this.$loading.hide();
      });
    },
    // 提交搜索
    submitSearch() {
      if (!/^[^\<>]*$/.test(this.searchTxt)) {
        this.$showCjToast({
          text: "输入内容不能包含特殊字符",
          type: 'warn',
          time: 2000
        });
        return;
      } else if (this.searchTxt.trim().length == 0) {
        this.$showCjToast({
          text: "搜索内容不能为空",
          type: 'warn',
          time: 2000
        });
        return;
      }
      this.$nextTick(() => {
        this.messages.push({content: this.searchTxt, record_id: this.messages.length + 1, replyMethod: 0});
        this.isSearch = 1;
        this.messageSearch();
        setTimeout(() => {
          this.domScrollIntoView();
        }, 300)
      })
    },
    // text/event-stream获取搜索信息
    messageSearch() {
      let postUrl = `${global.apiurl}aiChatSse/botChatCompletionsSse`;
      const data = {
        content: this.searchTxt,
        type: 4, // 默认值 4-腾讯Lke
        botType: 2, //  默认值 2-腾讯Lke知识库
        aikbId: this.baseInfo.aikbId, // 应用id
        sessionId: this.baseInfo.sessionId, // 会话id，开始传null
        aikbrId: this.baseInfo.aikbrId, // 关联id
      }
      let that = this;
      let searchAnswer = null;
      // AbortController 接口表示一个控制器对象，允许你根据需要中止一个或多个 Web 请求
      const ctrl = new AbortController();
      that.searchTxt = '';
      FetchEventSource.request(postUrl, {
        body: data,
        method: 'POST',
        controller: ctrl,
        onopen: (response) => {
          console.log('连接开始');
          that.isSearch = 0;
        },
        onmessage: (data) => {
          searchAnswer = data.payload;
          console.log('回答数据：' + searchAnswer.content);
          // 同一个回答record_id一样, 判断是否已存在回答
          if (that.messages.findIndex(item => item.record_id == searchAnswer.record_id) == -1) {
            that.messages.push(searchAnswer);
          }
        },
        onerror: (err) => {
          ctrl.abort();
          that.isSearch = -1;
          console.log('连接错误: ' + err.message);
        },
        onclose: () => {
          const answerContent = md.render(searchAnswer.content);
          console.log('answerContent: ' + answerContent);
          that.$set(that.messages[that.messages.length - 1], 'content', answerContent);
          that.domScrollIntoView();
          ctrl.abort();
          that.isSearch = 0;
          console.log('连接关闭');
        },
      });
    },
    // 清除会话
    cleanSession() {
      if (!this.messages || (this.messages && this.messages.length == 0)) return
      this.$loading.show({
        text: '加载中'
      });
      let postUrl = `${global.apiurl}aiCreationCenter/clearMsgRecord`;
      const data = {
        sessionId: this.baseInfo.sessionId, // 会话id
        aikbrId: this.baseInfo.aikbrId,
      }
      utilJs.postMethod(postUrl, data, res => {
        this.messages = [];
        this.searchTxt = '';
        // 加延迟是因为后端数据回调可能会存在还没更新的问题
        setTimeout(() => {
          this.getDescribeBaseRelate();
          window.scrollTo(0, 0);
        }, 1000)
        this.$loading.hide();
      }, () => {
        this.$loading.hide();
      });
    },
  },
}
</script>

<style>
.inputBox {
  border: 0;
  font-size: 0.6rem;
  color: #333;
}
.inputBox:-webkit-input-placeholder { /* WebKit browsers */
    color: #999;
    font-size: 0.6rem;
}
.inputBox:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
    font-size: 0.6rem;
    color: #999;
}
.inputBox:-moz-placeholder { /* Mozilla Firefox 19+ */
    font-size: 0.6rem;
    color: #999;
}
.inputBox:-ms-input-placeholder { /* Internet Explorer 10+ */
    font-size: 0.6rem;
    color: #999;
}
.inputBox:disabled {
  background-color: #fff !important;
}
/* .markdown-box是包裹markdown数据的容器 以下是特别样式得调整 */
.markdown-box table {
  max-width: max-content;
  width: max-content;
}

.markdown-box table th {
  color: #333;
  font-weight: 600;
  background-color: #f5f7fa;
}
.markdown-box table, .markdown-box th, .markdown-box td {
  border: 1px solid #ebedf0;
  border-collapse: collapse;
  padding: 0.2rem 0.4rem;
}
.markdown-box img {
  max-width: 100%;
}
.markdown-box li {
  margin-left: 0.6rem;
}
</style>